package ventpipe

import (
	"encoding/json"
	"evtest/evcs"
	"evtest/setting"
	"fmt"
	"time"
)

var TokenPipe *Token

type Token struct {
	pipe              *Pipe
	QueryTokenRsp     *evcs.QueryTokenResponse
	Interrupt         chan bool
	FetchRetry        int64
	FetchInterval     int64
	TokenValid        bool
	TokenFetching     bool
	TokenFetchTime    int64
	FetchTimer        *time.Timer
	TokenFetchInit    int64
	TokenFetchStep    int64
	TokenFetchCeiling int64
}

func NewToken(evConf *setting.EvConf) *Token {
	pipe := &Pipe{
		EvConf: evConf,
	}
	queryTokenRsp := &evcs.QueryTokenResponse{}
	tokenPipe := &Token{
		pipe:              pipe,
		QueryTokenRsp:     queryTokenRsp,
		Interrupt:         make(chan bool),
		FetchRetry:        0,
		FetchInterval:     2,
		TokenValid:        false,
		TokenFetching:     false,
		FetchTimer:        time.NewTimer(time.Second * 2),
		TokenFetchInit:    2,
		TokenFetchStep:    1,
		TokenFetchCeiling: 7200,
	}
	return tokenPipe
}

func (tp *Token) FetchClockRun() {
	for {
		select {
		case <-tp.FetchTimer.C:
			fmt.Printf("current time: %s\n", time.Now().Format("2006-01-02 15:04:05"))
		case <-tp.Interrupt:
			fmt.Printf("Interrupt. current time: %s\n", time.Now().Format("2006-01-02 15:04:05"))
		}
		tp.fetchControl()
	}
}

func (tp *Token) fetchControl() {
	checkingTime := time.Now().UnixNano()
	if tp.TokenFetching == true && tp.TokenFetchTime+tp.FetchInterval*1e9 > checkingTime+5*1e8 {
		fmt.Printf("token fetch request abortd: %s\n", time.Now().Format("2006-01-02 15:04:05"))
		fmt.Printf("abortd the fetch interval: %d\n", tp.FetchInterval)
		fmt.Printf("abortd the token valid status: %v\n", tp.TokenValid)
		fmt.Printf("abortd the token fetching status: %v\n", tp.TokenFetching)
		fmt.Printf("abortd the token fetching time: %d\n", tp.TokenFetchTime)
		fmt.Printf("abortd checking time: %d\n", checkingTime)
		return
	}
	tp.TokenValid = false
	tp.TokenFetching = true
	tp.TokenFetchTime = time.Now().UnixNano()
	tp.FetchRetry += 1
	tokenAvailableTime, ok := tp.tokenFetch()
	if ok {
		tp.TokenValid = true
		tp.TokenFetching = false
		tp.FetchInterval = tokenAvailableTime
		tp.FetchRetry = 0
		fmt.Println("fetch success")
	} else {
		if tp.FetchRetry == 1 {
			tp.FetchInterval = tp.TokenFetchInit
		} else {
			updatedInterval := tp.FetchInterval + tp.TokenFetchStep
			if updatedInterval >= tp.TokenFetchCeiling {
				updatedInterval = tp.TokenFetchCeiling
			}
			tp.FetchInterval = updatedInterval
		}
		fmt.Println("fetch failed")
	}
	fmt.Printf("the updated fetch interval: %d\n", tp.FetchInterval)
	fmt.Printf("the token valid status: %v\n", tp.TokenValid)
	fmt.Printf("the token fetching status: %v\n", tp.TokenFetching)
	fmt.Printf("the token fetching time: %d\n", tp.TokenFetchTime)
	fetchInterval := time.Duration(tp.FetchInterval)
	tp.FetchTimer.Reset(time.Second * fetchInterval)
}

func (tp *Token) tokenFetch() (int64, bool) {
	queryToken := evcs.QueryToken{
		OperatorID:     tp.pipe.EvConf.Account,
		OperatorSecret: tp.pipe.EvConf.Pin,
	}
	jsonParam, _ := queryToken.ToJson()
	reqData := tp.pipe.PrepareData(jsonParam)
	pipeRsp := tp.pipe.RequestAction("query_token", reqData, "")
	if pipeRsp.Err != nil {
		return 0, false
	}
	err := json.Unmarshal(pipeRsp.Data, tp.QueryTokenRsp)
	if err != nil {
		fmt.Printf("token response failed to parse to json:.\n")
		return 0, false
	}
	fmt.Printf("tp QueryTokenRsp: %#v\n", tp.QueryTokenRsp)
	if tp.QueryTokenRsp.SuccStat != 0 {
		fmt.Printf("token succ stat doesn't equal to zero.\n")
		return 0, false
	}
	fmt.Printf("response AccessToken: %#v.\n", tp.QueryTokenRsp.AccessToken)
	return int64(tp.QueryTokenRsp.TokenAvailableTime), true
}
